#ifndef _NE_STATE_H_
#define _NE_STATE_H_

#include <common/Event.h>

namespace ne
{
    // TODO: Any state can be changed to DefaultState
    //       and also DefaultState can be changed to any state
    // TODO: You can write your custom DefaultState
    //       or do nothing
    static const uint32_t FINITE_STATE_MACHINE_DEFAULT_STATE_ID = 0xFFFFFFFF;

    template<typename T> class FiniteStateMachine;

    template<typename T> class State
    {
        // TODO: If you need to call some of your custom interfaces
        //       in your custom derived FSM
        //       you must define friend class in your custom derived state class
        friend class FiniteStateMachine<T>;

        public:
            explicit State(T *pContent, const uint32_t id=FINITE_STATE_MACHINE_DEFAULT_STATE_ID)
                : mpContent(pContent),
                  mID(id)
            {
                assert(mpContent);
            }

            uint32_t getID() const
            {
                return mID;
            }

            virtual const std::type_info& type() const
            {
                return typeid(*this);
            }

        private:
            void _reset()
            {
                onReset();
            }

            uint32_t _event(Event &event)
            {
                return onEvent(event);
            }

            bool _enter(Event &event, const uint32_t lastStateID)
            {
                _reset();
                return onEnter(event, lastStateID);
            }

            bool _loop(Event &event)
            {
                return onLoop(event);
            }

            bool _exit(Event &event, const uint32_t nextStateID)
            {
                return onExit(event, nextStateID);
            }

        protected:
            virtual void onReset()
            {
            }

            // TODO: Interface for the state to deal with the event
            //       Return the state ID of next state
            // TODO: If the return ID is the same of mID
            //       it wont change the state
            // TODO: If you want to loop in the state, call onLoop
            virtual uint32_t onEvent(Event &event)
            {
                std::cout << "DefaultState onEvent" << std::endl;
                return mID;
            }

            // TODO: Interface for the state to deal with the event
            //       when enter the state
            //       Return if the state enter successfully
            virtual bool onEnter(Event &event, const uint32_t lastStateID)
            {
                std::cout << "DefaultState onEnter" << std::endl;
                return true;
            }

            // TODO: Interface for the state to deal with the event
            //       when loop the state
            //       and it do not call onEnter() and onExit()
            //       Return if the state loop successfully
            // TODO: If you want to call onEnter() or onExit()
            //       you need to do it in onLoop()
            // TODO: If you want to refuse the state loop
            //       you need to return false
            virtual bool onLoop(Event &event)
            {
                std::cout << "DefaultState onLoop" << std::endl;
                return true;
            }

            // TODO: Interface for the state to deal with the event
            //       when exit the state
            //       Return if the state exit successfully
            virtual bool onExit(Event &event, const uint32_t nextStateID)
            {
                std::cout << "DefaultState onExit" << std::endl;
                return true;
            }

            virtual ~State()
            {
            }

        private:
            State();

            State(const State &state);

            State& operator = (const State &state);

        protected:
            T *mpContent;
            uint32_t mID;
    };
}

#endif
